namespace WP7Contrib.Services.BingMaps.Model
{
    using System;
    using System.Device.Location;
    using Common;

    public sealed class ImageryMetadataCriterion : BaseModel,
                                                   ICriterion<ImageryMetadataCriterion>,
                                                   IEquatable<ImageryMetadataCriterion>,
                                                   IImageryMetadataForAnImagerySetCriterion,
                                                   IImageryMetadataForAnImagerySetAtSpecificLocationCriterion,
                                                   IImageryMetadataForBasicImagerySetAtSpecificLocationCriterion
    {
        private ImagerySet imagerySet;
        private GeoCoordinate centerPoint;
        private MetadataInclude? include;
        private int? orientation;
        private int? zoomLevel;
        private MapVersion? mapVersion;

        public ImageryMetadataCriterion()
        {
            this.Reset();
        }

        public ImagerySet ImagerySet
        {
            get
            {
                return this.imagerySet;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.imagerySet, value, () => this.ImagerySet);
            }
        }

        public GeoCoordinate CenterPoint
        {
            get
            {
                return this.centerPoint;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.centerPoint, value, () => this.CenterPoint);
            }
        }

        public MetadataInclude? Include
        {
            get
            {
                return this.include;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.include, value, () => this.Include);
            }
        }

        public int? Orientation
        {
            get
            {
                return this.orientation;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.orientation, value, () => this.Orientation);
            }
        }

        public int? ZoomLevel
        {
            get
            {
                return this.zoomLevel;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.zoomLevel, value, () => this.ZoomLevel);
            }
        }

        public MapVersion? MapVersion
        {
            get
            {
                return this.mapVersion;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.mapVersion, value, () => this.MapVersion);
            }
        }

        public ImageryMetadataCriterion Reset()
        {
            this.centerPoint = new GeoCoordinate();
            this.imagerySet = ImagerySet.Road;
            this.include = null;
            this.mapVersion = Model.MapVersion.V1;
            this.orientation = null;
            this.zoomLevel = null;
             
            return this;
        }

        public static bool operator ==(ImageryMetadataCriterion imc1, ImageryMetadataCriterion imc2)
        {
            return Equals(imc1, imc2);
        }

        public static bool operator !=(ImageryMetadataCriterion imc1, ImageryMetadataCriterion imc2)
        {
            return !Equals(imc1, imc2);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj))
            {
                return false;
            }

            return obj is ImageryMetadataCriterion && this.Equals((ImageryMetadataCriterion)obj);
        }

        public bool Equals(ImageryMetadataCriterion other)
        {
            if (ReferenceEquals(null, other))
            {
                return false;
            }

            if (this.imagerySet != other.imagerySet)
            {
                return false;
            }

            if (this.CenterPoint != other.CenterPoint)
            {
                return false;
            }

            if (this.Include != other.Include)
            {
                return false;
            }

            if (this.MapVersion != other.MapVersion)
            {
                return false;
            }

            if (this.Orientation != other.Orientation)
            {
                return false;
            }

            if (this.ZoomLevel != other.ZoomLevel)
            {
                return false;
            }

            return true;
        }

        public override int GetHashCode()
        {
            return this.CombineHashCodes(this.ImagerySet, this.CenterPoint, this.Include, this.MapVersion, this.Orientation, this.ZoomLevel);
        }

        IImageryMetadataForAnImagerySetCriterion ICloneable<IImageryMetadataForAnImagerySetCriterion>.ShallowClone()
        {
            return this.ShallowClone();
        }

        IImageryMetadataForAnImagerySetAtSpecificLocationCriterion ICloneable<IImageryMetadataForAnImagerySetAtSpecificLocationCriterion>.ShallowClone()
        {
            return this.ShallowClone();
        }

        IImageryMetadataForBasicImagerySetAtSpecificLocationCriterion ICloneable<IImageryMetadataForBasicImagerySetAtSpecificLocationCriterion>.ShallowClone()
        {
            return this.ShallowClone();
        }

        public ImageryMetadataCriterion ShallowClone()
        {
            var criterion = new ImageryMetadataCriterion
            {
                ImagerySet = this.ImagerySet,
                CenterPoint = this.CenterPoint,
                Include = this.Include,
                MapVersion = this.MapVersion,
                Orientation = this.Orientation,
                ZoomLevel = this.ZoomLevel
            };

            return criterion;
        }

        IImageryMetadataForAnImagerySetCriterion ICloneable<IImageryMetadataForAnImagerySetCriterion>.DeepClone()
        {
            return this.DeepClone();
        }

        IImageryMetadataForAnImagerySetAtSpecificLocationCriterion ICloneable<IImageryMetadataForAnImagerySetAtSpecificLocationCriterion>.DeepClone()
        {
            return this.DeepClone();
        }

        IImageryMetadataForBasicImagerySetAtSpecificLocationCriterion ICloneable<IImageryMetadataForBasicImagerySetAtSpecificLocationCriterion>.DeepClone()
        {
            return this.DeepClone();
        }

        public ImageryMetadataCriterion DeepClone()
        {
            var criterion = new ImageryMetadataCriterion
            {
                ImagerySet = this.ImagerySet,
                CenterPoint = new GeoCoordinate(this.CenterPoint.Latitude, this.CenterPoint.Longitude),
                Include = this.Include,
                MapVersion = this.MapVersion,
                Orientation = this.Orientation,
                ZoomLevel = this.ZoomLevel
            };

            return criterion;
        }
    }
}